package language.advanced.functional;

import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

class I {
    @Override
    public String toString() { return "I"; }
}

class O {
    @Override
    public String toString() { return "O"; }
}

public class TransformFunction {
    static Function<I,O> transform(Function<I,O> in) {
        return in.andThen(o -> {
            System.out.println(o);
            return o;
        });
    }
    public static void main(String[] args) {
        Function<I,O> f2 = transform(i -> {
            System.out.println(i);
            return new O();
        });
        O o = f2.apply(new I());

        //等价于
        Function<I,O> middle =  i -> {
            System.out.println(i);
            return new O();
        };
        // 将I 转换为O
        Function<I, O> returnFun = middle.andThen(k -> {
            System.out.println(k);
            return k;
        });
        returnFun.apply(new I());

    }
}

class FunctionComposition {
    static Function<String, String>
            f1 = s -> { System.out.println("执行f1");return s; },
            f2 = s -> { System.out.println("执行f2");return s; },
            f3 = s -> { System.out.println("执行f3");return s; },
            f4 = f1.compose(f2).andThen(f3);
    public static void main(String[] args) {
        System.out.println(f4.apply("执行f4"));
    }
    // 输出：
    //执行f2
    //执行f1
    //执行f3
    //执行f4
}

class PredicateComposition {
    static Predicate<String>
            p1 = s -> s.contains("bar"),
            p2 = s -> s.length() < 5,
            p3 = s -> s.contains("foo"),
            p4 = p1.negate().and(p2).or(p3),
            p5 = p1.negate().or(p2).and(p3);

    public static void main(String[] args) {
        Stream.of("bar", "foobar", "fon")
                .filter(p4)
                .forEach(System.out::println);
        //  等价于
        //  !s.contains("bar") && s.length() < 5 || s.contains("foo")
        //  (!p1 and p2) or p3

        System.out.println("------------");
        Stream.of("bar","bfoo", "foobadfsdsr", "fsdfsdffson")
                .filter(p5)
                .forEach(System.out::println);
        //  等价于 (!p1 or p2) and p3
    }
}